﻿(function () {
    "use strict";

    var i;
    var bingKey = 'An9oS8F0gfc9ARLGD_h7yentZoqZNmXHaByazvA-e3PzIAsPt-phst5tXfEnVNj3'; // Get your key from https://www.bingmapsportal.com/
    var censusKey = 'ba4b899c4fbcb88f16aee7f58c8ad1e517cc0fa5'; // Get your key from http://www.census.gov/developers
    var applicationData = Windows.Storage.ApplicationData.current;
    var localFolder = applicationData.localFolder
    var defaultZips = [32561, 98101, 11220];

    WinJS.Namespace.define("Data", {
        list: new WinJS.Binding.List([]),
        loadSettings: loadSettings,
        saveSettings: saveSettings,
        getBingData: getBingData,
        getPopulationData: getPopulationData,
        getCommuteData: getCommuteData,
        getHousingData: getHousingData
    });

    function saveSettings() {
        // save Data.list as a JSON string in an applicaiton text file (locales.txt)
        var settings = [];
        var item, population, housing, commute;
        for (i = 0; i < Data.list.length; i++) {
            item = Data.list.getAt(i);
            if (item == undefined) continue;
            population = (item.population) ? item.population.slice(0) : undefined;
            housing = (item.housing) ? item.housing.slice(0) : undefined;
            commute = (item.commute) ? item.commute.slice(0) : undefined;
            settings.push({
                city: item.city,
                state: item.state,
                FIPS: item.FIPS,
                zip: item.zip,
                satellite: item.satellite,
                population: population,
                housing: housing,
                commute: commute
            });
        }
        var json = JSON.stringify(settings);

        return localFolder.createFileAsync("locales.txt", Windows.Storage.CreationCollisionOption.replaceExisting).then(
            function (file) {
                console.info('Success: createFileAsync(locales.txt)', performance.now());
                return Windows.Storage.FileIO.writeTextAsync(file, json);
            },
            function (error) { console.error('Error: createFileAsync(locales.txt)', performance.now()); }).then(
            function (success) { console.info('Success: settings written to locales.txt', performance.now()) });
    }

    function loadSettings() {
        return localFolder.getFileAsync("locales.txt").then(
            function (file) {
                console.log('Success: getFileAsync(locales.txt)', performance.now());
                return Windows.Storage.FileIO.readTextAsync(file);

            }).then(function (result) {
                var settings = JSON.parse(result);
                Data.list.dataSource.beginEdits();
                for (i = 0; i < settings.length; i++) {
                    if (settings[i].population) settings[i].population = new WinJS.Binding.List(settings[i].population)
                    if (settings[i].commute) settings[i].commute = new WinJS.Binding.List(settings[i].commute);
                    if (settings[i].housing) settings[i].housing = new WinJS.Binding.List(settings[i].housing);
                    Data.list.dataSource.insertAtEnd(null, settings[i]);
                }
                Data.list.dataSource.endEdits();
                return;

            }).then(null, function () {
                // file not found; populate our list with the the default zips instead
                for (i = 0; i < defaultZips.length; i++) {
                    Data.getBingData(defaultZips[i]).then(
                        function (result) {
                            Data.list.dataSource.beginEdits();
                            Data.list.dataSource.insertAtEnd(null, result);
                            Data.list.dataSource.endEdits();
                            Data.saveSettings(result);
                        },
                        function (error) { console.error('Error: getBingData()', defaultZips[i], performance.now()); }
                    );
                }
            });
    }

    function getBingData(zip) {

        // validate zip code
        if (!/^\d{5}(-\d{4})?$/.test(zip)) return;

        var url = 'http://dev.virtualearth.net/REST/v1/Locations?q=' + zip + '&o=json&key=' + bingKey;
        var xhr = WinJS.xhr({ url: url }).then(
                function (result) {
                    if (result.status != 200) return false;

                    var json = JSON.parse(result.response).resourceSets[0].resources[0];
                    var data = {
                        FIPS: _getState(json.address.adminDistrict).FIPS,
                        zip: json.address.postalCode,
                        city: json.address.locality,
                        state: json.address.adminDistrict,
                        satellite: "url('http://dev.virtualearth.net/REST/v1/Imagery/Map/Aerial/" + json.geocodePoints[0].coordinates[0] + "," + json.geocodePoints[0].coordinates[1] + "/18?mapSize=900,800&key=" + bingKey + "');",
                        population: undefined,
                        housing: undefined,
                        commute: undefined
                    };

                    console.info('Success: WinJS.xhr()', url, performance.now());
                    return data;
                },
                function (error) { console.error('Error: WinJS.xhr()', url, performance.now()); });
        return xhr;
    }

    function getPopulationData(item) {

        if (item.population) return WinJS.Promise.as(item.population);

        var url = "http://api.census.gov/data/2011/acs5?get=B01001_001E,B01001_002E,B01001_003E,B01001_004E,B01001_005E,B01001_006E,B01001_007E,B01001_008E,B01001_009E,B01001_010E,B01001_011E,B01001_012E,B01001_013E,B01001_014E,B01001_015E,B01001_016E,B01001_017E,B01001_018E,B01001_019E,B01001_020E,B01001_021E,B01001_022E,B01001_023E,B01001_024E,B01001_025E,B01001_026E,B01001_027E,B01001_028E,B01001_029E,B01001_030E,B01001_031E,B01001_032E,B01001_033E,B01001_034E,B01001_035E,B01001_036E,B01001_037E,B01001_038E,B01001_039E,B01001_040E,B01001_041E,B01001_042E,B01001_043E,B01001_044E,B01001_045E,B01001_046E,B01001_047E,B01001_048E,B01001_049E&for=zip+code+tabulation+area:" + item.zip + "&key=" + censusKey;
        var xhr = WinJS.xhr({ url: url }).then(
            function (result) {
                if (result.status != 200) return false;

                var json = JSON.parse(result.response);
                var data = _formatPopulationData(json);
                var list = new WinJS.Binding.List(data);
                Data.list.dataSource.beginEdits();
                item.population = list;
                Data.list.dataSource.endEdits();

                saveSettings();

                console.info('Success: WinJS.xhr()', url, performance.now());
                return list;
            },
            function (error) { console.error('Error: WinJS.xhr()', url, performance.now()); });
        return xhr;
    }

    function getCommuteData(item) {

        if (item.commute) return WinJS.Promise.as(item.commute);

        var url = "http://api.census.gov/data/2011/acs5?get=B08301_001E,B08301_002E,B08301_003E,B08301_004E,B08301_005E,B08301_006E,B08301_007E,B08301_008E,B08301_009E,B08301_010E,B08301_011E,B08301_012E,B08301_013E,B08301_014E,B08301_015E,B08301_016E,B08301_017E,B08301_018E,B08301_019E,B08301_020E,B08301_021E&for=zip+code+tabulation+area:" + item.zip + "&key=" + censusKey;
        return WinJS.xhr({ url: url }).then(
            function (result) {
                if (result.status != 200) return false;

                var json = JSON.parse(result.response);
                var data = _formatCommuteData(json);
                var list = new WinJS.Binding.List(data);
                Data.list.dataSource.beginEdits();
                item.commute = list;
                Data.list.dataSource.endEdits();

                saveSettings();

                console.info('Success: WinJS.xhr()', url, performance.now());
                return list;
            },
            function (error) { console.error('Error: WinJS.xhr()', url, performance.now()); });
        return xhr;
    }

    function getHousingData(item) {

        if (item.housing) return WinJS.Promise.as(item.housing);

        var url = 'http://api.census.gov/data/2010/sf1?get=H0040001,H0040002,H0040003,H0040004&for=zip+code+tabulation+area:' + item.zip + '&in=state:' + item.FIPS + '&key=' + censusKey;
        var xhr = WinJS.xhr({ url: url }).then(
            function (result) {
                if (result.status != 200) return false;
                var json = JSON.parse(result.response);
                var data = _formatHousingData(json);
                var list = new WinJS.Binding.List(data);
                Data.list.dataSource.beginEdits();
                item.housing = list;
                Data.list.dataSource.endEdits();
                saveSettings();

                console.info('Success: WinJS.xhr()', url, performance.now());
                return list;
            },
            function (error) { console.error('Error: WinJS.xhr()', url, performance.now()); });
        return xhr;
    }

    function _formatPopulationData(data) {

        var males = [
            {
                censusCodes: ["B01001_003E", "B01001_004E"],
                ageRange: '0-9',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_005E", "B01001_006E", "B01001_007E"],
                ageRange: '10-19',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_008E", "B01001_009E", "B01001_010E", "B01001_01E"],
                ageRange: '20-29',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_012E", "B01001_013E"],
                ageRange: '30-39',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_014E", "B01001_015E"],
                ageRange: '40-49',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_016E", "B01001_017E"],
                ageRange: '50-59',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_018E", "B01001_019E", "B01001_020E", "B01001_021E"],
                ageRange: '60-69',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_022E", "B01001_023E"],
                ageRange: '70-79',
                gender: 'male'
            },
            {
                censusCodes: ["B01001_024E", "B01001_025E"],
                ageRange: '80+',
                gender: 'male'
            }
        ];

        var females = [
            {
                censusCodes: ["B01001_027E", "B01001_028E"],
                ageRange: '0-9',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_029E", "B01001_030E", "B01001_031E"],
                ageRange: '10-19',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_032E", "B01001_033E", "B01001_034E", "B01001_035E"],
                ageRange: '20-29',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_036E", "B01001_037E"],
                ageRange: '30-39',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_038E", "B01001_039E"],
                ageRange: '40-49',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_040E", "B01001_041E"],
                ageRange: '50-59',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_042E", "B01001_043E", "B01001_044E", "B01001_045E"],
                ageRange: '60-69',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_046E", "B01001_047E"],
                ageRange: '70-79',
                gender: 'female'
            },
            {
                censusCodes: ["B01001_048E", "B01001_049E"],
                ageRange: '80+',
                gender: 'female'
            }
        ];

        males = _sumCensusData(males, data);
        females = _sumCensusData(females, data);

        var fdata = [];
        for (i = 0; i < males.length; i++) {
            fdata[i] = {
                maleCensusCodes: males[i].censusCodes,
                maleCount: males[i].count,
                malePercent: males[i].percent,
                ageRange: males[i].ageRange,
                row: i + 1
            }
        }
        for (i = 0; i < fdata.length; i++) {
            fdata[i].femaleCount = females[i].count;
            fdata[i].femalePercent = females[i].percent;
        }

        return fdata;
    }

    function _formatCommuteData(data) {

        var fdata = [
            {
                // automobile, taxi, motorcycle
                censusCodes: ["B08301_003E", "B08301_016E", "B08301_017E"],
                name: "car",
                bgImage: "url('/images/car.png')",
            },
            {
                // carpool and public transit
                censusCodes: ["B08301_005E", "B08301_006E", "B08301_007E", "B08301_008E", "B08301_009E", "B08301_011E", "B08301_012E", "B08301_013E", "B08301_014E", "B08301_015E"],
                name: "transit",
                bgImage: "url('/images/bus.png')",
            },
            {
                // bicycle, walk
                censusCodes: ["B08301_018E", "B08301_019E"],
                name: 'self',
                bgImage: "url('/images/bike.png')",
            }
        ];

        fdata = _sumCensusData(fdata, data);

        return fdata;
    }

    function _formatHousingData(data) {

        var fdata = [
            {
                censusCodes: ["H0040002", "H0040003"],
                type: "own"
            },
            {
                censusCodes: ["H0040004"],
                type: 'rent'
            }
        ];

        fdata = _sumCensusData(fdata, data);

        return fdata;
    }

    function _sumCensusData(fdata, data) {

        // counters
        var f, c, d, i, total = 0;

        // loop through formatted data
        for (f = 0; f < fdata.length; f++) {

            // loop through census codes within each catagory
            for (c = 0; c < fdata[f].censusCodes.length; c++) {

                // loop through census data
                for (d = 0; d < data[0].length; d++) {

                    // do the census codes match?
                    if (data[0][d] === fdata[f].censusCodes[c]) {

                        i = parseInt(data[1][d]);

                        // this should never happen
                        if (isNaN(i)) {
                            console.warn('census data returns NaN');
                            break;
                        }

                        // add to the current population count for this category
                        fdata[f].count = (fdata[f].count == undefined) ? i : fdata[f].count + i;

                        // keep a running total of the population across categories
                        total += i;
                        break;
                    }
                }
            }
        }

        // calculate the percent for each population category
        for (f = 0; f < fdata.length; f++) {
            fdata[f].percent = Math.round(fdata[f].count / total * 100) + "%";
        }

        return fdata;
    }

    function _getState(abbr) {
        var states = [
            { FIPS: '01', name: 'Alabama', abbr: 'AL' },
            { FIPS: '02', name: 'Alaska', abbr: 'AK' },
            { FIPS: '04', name: 'Arizona', abbr: 'AZ' },
            { FIPS: '05', name: 'Arkansas', abbr: 'AR' },
            { FIPS: '06', name: 'California', abbr: 'CA' },
            { FIPS: '08', name: 'Colorado', abbr: 'CO' },
            { FIPS: '09', name: 'Connecticut', abbr: 'CT' },
            { FIPS: '10', name: 'Delaware', abbr: 'DE' },
            { FIPS: '11', name: 'District of Columbia', abbr: 'DC' },
            { FIPS: '12', name: 'Florida', abbr: 'FL' },
            { FIPS: '13', name: 'Georgia', abbr: 'GA' },
            { FIPS: '15', name: 'Hawaii', abbr: 'HI' },
            { FIPS: '16', name: 'Idaho', abbr: 'ID' },
            { FIPS: '17', name: 'Illinois', abbr: 'IL' },
            { FIPS: '18', name: 'Indiana', abbr: 'IN' },
            { FIPS: '19', name: 'Iowa', abbr: 'IA' },
            { FIPS: '20', name: 'Kansas', abbr: 'KS' },
            { FIPS: '21', name: 'Kentucky', abbr: 'KY' },
            { FIPS: '22', name: 'Louisiana', abbr: 'LA' },
            { FIPS: '23', name: 'Maine', abbr: 'ME' },
            { FIPS: '24', name: 'Maryland', abbr: 'MD' },
            { FIPS: '25', name: 'Massachusetts', abbr: 'MA' },
            { FIPS: '26', name: 'Michigan', abbr: 'MI' },
            { FIPS: '27', name: 'Minnesota', abbr: 'MN' },
            { FIPS: '28', name: 'Mississippi', abbr: 'MS' },
            { FIPS: '29', name: 'Missouri', abbr: 'MO' },
            { FIPS: '30', name: 'Montana', abbr: 'MT' },
            { FIPS: '31', name: 'Nebraska', abbr: 'NE' },
            { FIPS: '32', name: 'Nevada', abbr: 'NV' },
            { FIPS: '33', name: 'New Hampshire', abbr: 'NH' },
            { FIPS: '34', name: 'New Jersey', abbr: 'NJ' },
            { FIPS: '35', name: 'New Mexico', abbr: 'NM' },
            { FIPS: '36', name: 'New York', abbr: 'NY' },
            { FIPS: '37', name: 'North Carolina', abbr: 'NC' },
            { FIPS: '38', name: 'North Dakota', abbr: 'ND' },
            { FIPS: '39', name: 'Ohio', abbr: 'OH' },
            { FIPS: '40', name: 'Oklahoma', abbr: 'OK' },
            { FIPS: '41', name: 'Oregon', abbr: 'OR' },
            { FIPS: '42', name: 'Pennsylvania', abbr: 'PA' },
            { FIPS: '44', name: 'Rhode Island', abbr: 'RI' },
            { FIPS: '45', name: 'South Carolina', abbr: 'SC' },
            { FIPS: '46', name: 'South Dakota', abbr: 'SD' },
            { FIPS: '47', name: 'Tennessee', abbr: 'TN' },
            { FIPS: '48', name: 'Texas', abbr: 'TX' },
            { FIPS: '49', name: 'Utah', abbr: 'UT' },
            { FIPS: '50', name: 'Vermont', abbr: 'VT' },
            { FIPS: '51', name: 'Virginia', abbr: 'VA' },
            { FIPS: '53', name: 'Washington', abbr: 'WA' },
            { FIPS: '54', name: 'West Virginia', abbr: 'WV' },
            { FIPS: '55', name: 'Wisconsin', abbr: 'WI' },
            { FIPS: '56', name: 'Wyoming', abbr: 'WY' }
        ];

        for (i = 0; i < states.length; i++) {
            if (states[i].abbr === abbr) {
                return states[i];
            }
        }
    }

})();